package com.sky.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.sky.constant.JwtClaimsConstant;
import com.sky.constant.MessageConstant;
import com.sky.constant.PasswordConstant;
import com.sky.constant.StatusConstant;
import com.sky.context.BaseContext;
import com.sky.dto.EmployeeDTO;
import com.sky.dto.EmployeeLoginDTO;
import com.sky.dto.EmployeePageQueryDTO;
import com.sky.entity.Employee;
import com.sky.exception.AccountLockedException;
import com.sky.exception.AccountNotFoundException;
import com.sky.exception.PasswordErrorException;
import com.sky.mapper.EmployeeMapper;
import com.sky.properties.JwtProperties;
import com.sky.result.PageResult;
import com.sky.service.EmployeeService;
import com.sky.utils.JwtUtil;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;

/*
 * 员工管理的service
 * service层的作用：
 *   调用mapper层的方法查询数据库，如果需要将查询到的数据进行逻辑处理就在service层处理
 *   返回结果给Controller层
 * */
@Slf4j
@Service
public class EmployeeServiceImpl implements EmployeeService {
    /* @Autowired进行自动依赖注入，对类、成员变量、成员方法及构造方法进行标注，完成bean自动装配的工作*/
    @Autowired
    private EmployeeMapper employeeMapper;
    @Autowired
    private JwtProperties jwtProperties;

    /**
     * 员工登录
     *
     * @param employeeLoginDTO
     * @return
     * @info 接收Controller层传递过来的用户名密码，调用mapper层的方法查询数据中用户是否存在然后进行各种异常判断(用户名不存在、密码不对、账号被锁定) Service->Mapper
     */
    public Employee login(EmployeeLoginDTO employeeLoginDTO) {
        // 获取用户名以及密码
        String username = employeeLoginDTO.getUsername();
        String password = employeeLoginDTO.getPassword();
        //调用Mapper层的方法根据用户名查询数据库中的数据(查询用户是否存在)
        Employee employee = employeeMapper.getByUsername(username);
        /*处理各种异常情况(用户名不存在、密码不对、账号被锁定)*/
        //账号不存在，如果employee为null则没有在数据库中查询到数据证明用户不存在
        if (employee == null) throw new AccountNotFoundException(MessageConstant.ACCOUNT_NOT_FOUND);
        /*对前端传递过来的password进行MD5加密处理，判断密码是否错误*/
        password = DigestUtils.md5DigestAsHex(password.getBytes());
        if (!password.equals(employee.getPassword())) throw new PasswordErrorException(MessageConstant.PASSWORD_ERROR);
        //账号被锁定
        if (employee.getStatus() == StatusConstant.DISABLE) throw new AccountLockedException(MessageConstant.ACCOUNT_LOCKED);
        //返回实体对象给Controller层
        return employee;
    }

    /**
     * 新增员工
     *
     * @param employeeDTO
     * @return void
     * @info 接收Controller层传递过来的员工数据调用Service层的方法并且传递员工信息，Service层再去调用Mapper层的方法去数据库中添加一位员工  Service->Mapper
     */
    @Override
    public void addEmployee(EmployeeDTO employeeDTO, HttpServletRequest request) {
        // 创建一个employee实体类对象
        Employee employee = new Employee();
        // 使用BeanUtils.copyProperties()方法进行属性值的复制。该方法接收两个参数：源对象和目标对象。它会自动匹配属性名相同的属性，并将源对象的属性值复制到目标对象中
        BeanUtils.copyProperties(employeeDTO, employee);

        /*
        从请求头中获取令牌
        String token = request.getHeader(jwtProperties.getAdminTokenName());
        Claims claims = JwtUtil.parseJWT(jwtProperties.getAdminSecretKey(), token);
        Long empId = Long.valueOf(claims.get(JwtClaimsConstant.EMP_ID).toString());
        */

        // 设置员工状态、员工默认密码、员工创建时间、员工更新时间、创建人ID和修改人ID
        employee.setStatus(StatusConstant.ENABLE);
        employee.setPassword(DigestUtils.md5DigestAsHex(PasswordConstant.DEFAULT_PASSWORD.getBytes()));
        employee.setUpdateTime(LocalDateTime.now());
        employee.setCreateTime(LocalDateTime.now());
        employee.setCreateUser(BaseContext.getCurrentId());
        employee.setUpdateUser(BaseContext.getCurrentId());
        // 调用Mapper层的方法添加员工
        employeeMapper.insertEmployee(employee);
    }

    /**
     * 查询所有员工(支持分页查询、模糊查询)
     *
     * @param employeePageQueryDTO
     * @return PageResult
     * @info 接收Controller层传递过来的分页参数调用Service层的方法并且传递分页，Service层再去调用Mapper层的方法去数据库中查询员工  Service->Mapper
     */
    @Override
    public PageResult fetchAllEmployees(EmployeePageQueryDTO employeePageQueryDTO) {
        // 开始分页传递页码、每页展示数据条数
        PageHelper.startPage(employeePageQueryDTO.getPage(), employeePageQueryDTO.getPageSize());
        // 调用Mapper层的分页方法并且返回员工集合，进行数据转换
        Page<Employee> p = (Page<Employee>) employeeMapper.selectAllEmployee(employeePageQueryDTO.getName());
        // 返回员工数据集合数据给Controller层
        return new PageResult(p.getTotal(), p.getResult());
    }

    /**
     * 删除员工
     *
     * @param id
     * @return void
     * @info 接收Controller层传递过来的员工id调用Service层的方法并且传递员工id，Service层再去调用Mapper层的方法去数据库中删除员工  Service->Mapper
     */
    @Override
    public void deleteEmployee(Long id) {
        employeeMapper.deleteEmployeeById(id);
    }

    /**
     * 修改员工的启用或者禁用状态
     *
     * @param status
     * @param id
     * @return void
     * @info 接收Controller层传递过来的status以及id调用Mapper层的方法修改数据库表中的员工状态 Service->Mapper
     */
    public void openOrCloseEmployeeStatus(Integer status, Long id) {
        Employee employee = Employee.builder().status(status).id(id).updateTime(LocalDateTime.now()).updateUser(BaseContext.getCurrentId()).build();
        employeeMapper.updateEmployeeStatusById(employee);
    }

    /**
     * 查询员工
     *
     * @param id
     * @return void
     * @info 接收Controller层传递过来的员工id调用Mapper层的方法查询数据库表中的员工 Service->Mapper
     */
    @Override
    public Employee fetchEmployeeById(Long id) {
        return employeeMapper.selectEmployeeById(id);
    }

    /**
     * 编辑员工
     *
     * @param employee
     * @return void
     * @info 接收Controller层传递过来的员工信息调用Mapper层的方法往数据库表中修改员工 Service->Mapper
     */
    public void updateEmployee(EmployeeDTO employeeDTO) {
        Employee employee = new Employee();
        BeanUtils.copyProperties(employeeDTO, employee);
        employee.setUpdateUser(BaseContext.getCurrentId());
        employee.setUpdateTime(LocalDateTime.now());
        employeeMapper.updateEmployee(employee);
    }
}
